﻿/* 
 * Copyright (c) 2011 Jeff Zhang
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of 
 * this software and associated documentation files (the "Software"), 
 * to deal in the Software without restriction, including without limitation the rights to use, 
 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 
 * and to permit persons to whom the Software is furnished to do so, 
 * subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included 
 * in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

using System;
using System.Collections;

namespace Cipher {
    public class NodeCollection : IList {
        private ArrayList _list;

        public NodeCollection() {
            this._list = new ArrayList();
        }

        public NodeCollection(int capacity) {
            this._list = new ArrayList(capacity);
        }

        public bool IsReadOnly { get; private set; }
        public int Count { get { return this._list.Count; } }

        public int Add(Node node) {
            node.Index = this._list.Count;
            return this._list.Add(node);
        }

        public void AddRange(Node[] nodes) {
            int c = this._list.Count;
            for (int i = 0; i < nodes.Length; i++) {
                nodes[i].Index = c + i;
            }

            this._list.AddRange(nodes);
        }

        public void Clear() {
            this._list.Clear();
        }

        public bool Contains(Node node) {
            return this._list.Contains(node);
        }

        public int IndexOfKey(string key) {
            foreach (Node node in this._list) {
                if (node.Key == key) {
                    return node.Index;
                }
            }

            return -1;
        }

        public virtual void Remove(Node node) {
            int index = IndexOf(node);

            if (index >= 0) {
                for (int i = index + 1; i < this._list.Count; i++) {
                    ((Node)this._list[i]).Index = i - 1;
                }

                this._list.Remove(node);
            }
        }

        public virtual void RemoveAt(int index) {
            if (index < 0 || index >= this._list.Count) {
                throw new ArgumentOutOfRangeException("index");
            }

            for (int i = index + 1; i < this._list.Count; i++) {
                ((Node)this._list[i]).Index = i - 1;
            }
            
            this._list.RemoveAt(index);
        }

        public int IndexOf(Node node) {
            return this._list.IndexOf(node);
        }

        public void Insert(int index, Node value) {
            if (index < 0 || index >= this._list.Count) {
                throw new ArgumentOutOfRangeException("index");
            }

            value.Index = ((Node)this._list[index]).Index;

            this._list.Insert(index, value);
        }

        public bool IsFixedSize {
            get { return this._list.IsFixedSize; }
        }

        public Node this[int index] {
            get {
                if (index < 0 || index >= this._list.Count) {
                    throw new ArgumentOutOfRangeException("index");
                }

                return (Node)this._list[index];
            }
            set {
                if (value == null) {
                    throw new ArgumentNullException("value");
                }

                if (index < 0 || index >= this._list.Count) {
                    throw new ArgumentOutOfRangeException("index");
                }

                value.Index = ((Node)this._list[index]).Index;

                this._list[index] = value;
            }
        }

        public Node this[string key] {
            get {
                int index = IndexOfKey(key);

                if (index < 0) {
                    throw new ArgumentOutOfRangeException("key");
                }

                return (Node)this._list[index];
            }
            set {
                if (value == null) {
                    throw new ArgumentNullException("value");
                }

                int index = IndexOfKey(key);

                if (index < 0) {
                    throw new ArgumentOutOfRangeException("key");
                }

                value.Index = ((Node)this._list[index]).Index;

                this._list[index] = value;
            }
        }

        public void CopyTo(Array array, int index) {
            this._list.CopyTo(array, index);
        }

        public bool IsSynchronized {
            get { return this._list.IsSynchronized; }
        }

        public object SyncRoot {
            get { return this._list.SyncRoot; }
        }

        public IEnumerator GetEnumerator() {
            return this._list.GetEnumerator();
        }

        int IList.Add(object value) {
            if (value == null) {
                throw new ArgumentNullException("value");
            }

            if (!(value is Node)) {
                throw new ArgumentException("value");
            } else {
                return this.Add((Node)value);
            }
        }

        bool IList.Contains(object value) {
            if (value == null) {
                throw new ArgumentNullException("value");
            }

            if (!(value is Node)) {
                throw new ArgumentException("value");
            } else {
                return this.Contains((Node)value);
            }
        }

        int IList.IndexOf(object value) {
            if (value == null) {
                throw new ArgumentNullException("value");
            }

            if (!(value is Node)) {
                throw new ArgumentException("value");
            } else {
                return this.IndexOf((Node)value);
            }
        }

        void IList.Insert(int index, object value) {
            if (value == null) {
                throw new ArgumentNullException("value");
            }

            if (!(value is Node)) {
                throw new ArgumentException("value");
            } else {
                this.Insert(index, (Node)value);
            }
        }

        void IList.Remove(object value) {
            if (value == null) {
                throw new ArgumentNullException("value");
            }

            if (!(value is Node)) {
                throw new ArgumentException("value");
            } else {
                this.Remove((Node)value);
            }
        }

        object IList.this[int index] {
            get {
                return this[index];
            }
            set {
                if (value == null) {
                    throw new ArgumentNullException("value");
                }

                if (!(value is Node)) {
                    throw new ArgumentException("value");
                } else {
                    this[index] = (Node)value;
                }
            }
        }
    }
}
